package com.nami.logic.rocketmq.consumer;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.nami.basic.bo.client.ClientRespBO;
import com.nami.basic.bo.mq.DownLoginWrap;
import com.nami.basic.constants.DownTopicConst;
import com.nami.basic.constants.UpTopicConst;
import com.nami.basic.enums.DownMsgErrorCode;
import com.nami.basic.enums.protocol.DownCMDEnum;
import com.nami.basic.packet.Packet;
import com.nami.basic.request.upmsg.LoginMqWrap;
import com.nami.logic.enums.DeviceEnum;
import com.nami.logic.serializer.Serializer;
import com.nami.logic.service.DownMsgSender;
import com.nami.logic.service.PacketFactory;
import com.nami.logic.upmsg.UpMsgLoginReq;
import com.nami.store.api.bo.UserDevice;
import com.nami.store.api.bo.UserWrap;
import com.nami.store.api.request.cache.CacheDelReq;
import com.nami.store.api.service.RemoteL2CacheService;
import com.nami.store.api.service.RemoteUserService;
import com.nami.store.api.response.user.UserDTO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.dromara.common.core.utils.IdentityUtil;
import org.dromara.common.json.utils.JsonUtils;
import org.jetbrains.annotations.NotNull;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.nami.basic.constants.UpTopicConst.LOGIN_CONSUMER_GROUP;

@Slf4j
@Component
@AllArgsConstructor
@RocketMQMessageListener(topic = UpTopicConst.LOGIN_TOPIC,
    consumerGroup = LOGIN_CONSUMER_GROUP,
    consumeMode = ConsumeMode.CONCURRENTLY)
public class LoginConsumer implements RocketMQListener<String> {

    private final DownMsgSender mqSender;

    private final PacketFactory packetFactory;

    private final RedissonClient redissonClient;

    @DubboReference
    private final RemoteUserService userService;

    @DubboReference
    private final RemoteL2CacheService cacheService;


    @Override
    public void onMessage(String message) {
        try {
//            log.info("[login-consumer] begin. message:{}", message);
            TimeInterval timer = DateUtil.timer();
            final LoginMqWrap body = JSONUtil.toBean(message, LoginMqWrap.class);
            Packet packet = body.getPacket();
            final UpMsgLoginReq loginRequest = Serializer.prototype(packet.getSerial()).deserialize(packet.getBody(), UpMsgLoginReq.class);

            log.info("[login] login param:{}", JsonUtils.toJsonString(loginRequest));

            // 校验
            if (ObjectUtil.isNull(loginRequest)
                || null == loginRequest.getCurrTime()
                || StringUtils.isBlank(loginRequest.getUserId())
                || StringUtils.isBlank(loginRequest.getAppKey())
                || null == loginRequest.getDeviceType()) {
                // 组装ws返回内容
                ClientRespBO clientResp = new ClientRespBO();
                clientResp.setCode(DownMsgErrorCode.REQUEST_PARAMS_ERROR.getCode());
                clientResp.setMsg(DownMsgErrorCode.REQUEST_PARAMS_ERROR.getMsg());
                packet.setCmd(DownCMDEnum.LOGIN.getCode());
                packet.setBody(Serializer.prototype(packet.getSerial()).serialize(clientResp));

                DownLoginWrap resp = new DownLoginWrap();
                resp.setSuccess(Boolean.FALSE);
                resp.setPacket(packet);
                resp.setTempFingerprint(body.getTempFingerprint());
                mqSender.syncSendByMq(DownTopicConst.LOGIN_TOPIC, body.getMqTags(), JsonUtils.toJsonString(resp));
                return;
            }

            if (DateUtil.between(new Date(), new Date(loginRequest.getCurrTime()), DateUnit.MINUTE) >= 3) {
                log.warn("[login] 消息过期，不予处理.  mq消息消费成功！userId={}", loginRequest.getUserId());
                return;
            }

            String identityNo = IdentityUtil.buildIdentityNo(loginRequest.getUserId(), loginRequest.getDeviceType());
            UserDTO userInfo = userService.getUserByUserId(loginRequest.getAppKey(), loginRequest.getUserId());
            // 处理查无此人
            if (ObjectUtil.isNull(userInfo)) {
                log.info("[login] 【userNo={}】查无此人", loginRequest.getUserId());
                // 组装ws返回内容
                ClientRespBO clientResp = new ClientRespBO();
                clientResp.setCode(DownMsgErrorCode.USER_NOT_EXIST.getCode());
                clientResp.setMsg(DownMsgErrorCode.USER_NOT_EXIST.getMsg());
                packet.setCmd(DownCMDEnum.LOGIN.getCode());
                packet.setBody(Serializer.prototype(packet.getSerial()).serialize(clientResp));

                DownLoginWrap resp = new DownLoginWrap();
                resp.setSuccess(Boolean.FALSE);
                resp.setPacket(packet);
                resp.setTempFingerprint(body.getTempFingerprint());
                mqSender.syncSendByMq(DownTopicConst.LOGIN_TOPIC, body.getMqTags(), JsonUtils.toJsonString(resp));
                return;
            }

            List<UserDevice> devices = null;
            RLock lock = redissonClient.getLock("nami:" + loginRequest.getAppKey() + ":user:lock:" + loginRequest.getUserId());
            try {
                lock.lock(2, TimeUnit.SECONDS);
                final UserWrap user = cacheService.getOnrUser(loginRequest.getAppKey(), loginRequest.getUserId());
                if (user != null) {
                    List<UserDevice> deviceInfos = user.getDeviceInfos();
                    if (CollUtil.isNotEmpty(deviceInfos)) {
                        UserDevice deviceInfo = deviceInfos.stream()
                            .filter(item -> item.getDeviceType().equals(loginRequest.getDeviceType())).findFirst()
                            .orElse(null);
                        if (ObjectUtil.isNotNull(deviceInfo)) {
                            log.info("[login] clientIp:{}，now:{}", body.getClientIp(), deviceInfo.getUserIp());
                            if (StringUtils.isNotBlank(body.getClientIp()) && deviceInfo.getUserIp().equals(body.getClientIp())) {
                                //
                                // 组装ws返回内容
                                ClientRespBO clientResp = new ClientRespBO();
                                clientResp.setCode(DownMsgErrorCode.USER_LOGGED.getCode());
                                clientResp.setMsg(DownMsgErrorCode.USER_LOGGED.getMsg());
                                packet.setCmd(DownCMDEnum.LOGIN.getCode());
                                packet.setBody(Serializer.prototype(packet.getSerial()).serialize(clientResp));

                                DownLoginWrap resp = new DownLoginWrap();
                                resp.setSuccess(Boolean.FALSE);
                                resp.setPacket(packet);
                                resp.setTempFingerprint(body.getTempFingerprint());
                                mqSender.syncSendByMq(DownTopicConst.LOGIN_TOPIC, body.getMqTags(), JsonUtils.toJsonString(resp));
                                return;
                            }

                            // 不属于相同ip 属于踢他下线
                            CacheDelReq cacheDelDTO = new CacheDelReq();
                            cacheDelDTO.setAppKey(userInfo.getAppKey());
                            cacheDelDTO.setUserId(loginRequest.getUserId());
                            cacheDelDTO.setDeviceType(loginRequest.getDeviceType());
                            cacheService.removeOfflineUser(cacheDelDTO);
                        }
                        devices = deviceInfos.stream().filter(item -> !item.getDeviceType().equals(loginRequest.getDeviceType())).collect(Collectors.toList());

                    }

                }
                // 缓存添加用户登录信息
                cacheService.updOnrUser(makeUserWrap(body, loginRequest, userInfo, devices));
                log.info("[login] 用户[{}]登录成功, 设备类型==>{}, 指纹:{}, 使用{}ms", userInfo.getNickname(), DeviceEnum.getDeviceNameByValue(loginRequest.getDeviceType()), body.getTempFingerprint(), timer.interval());
            } finally {
                lock.unlock();
            }


            ClientRespBO client = new ClientRespBO();
            client.setCode(DownMsgErrorCode.SUCCESS.getCode());
            client.setMsg(DownMsgErrorCode.SUCCESS.getMsg());
            Packet respPacket = packetFactory.newPacket(DownCMDEnum.LOGIN.getCode(), client);
            DownLoginWrap downWrap = new DownLoginWrap();
            downWrap.setSuccess(Boolean.TRUE); // 登录成功标识
            downWrap.setTempFingerprint(body.getTempFingerprint());
            downWrap.setIdentityNo(identityNo);
            downWrap.setUserId(userInfo.getUserId());
            downWrap.setAppKey(userInfo.getAppKey());
            downWrap.setDeviceType(loginRequest.getDeviceType());
            downWrap.setImei("test");
            downWrap.setPacket(respPacket);
//            loginService.loginSuccess(request);
            mqSender.syncSendByMq(DownTopicConst.LOGIN_TOPIC, body.getMqTags(), JsonUtils.toJsonString(downWrap));
        } catch (Exception var3) {
            var3.printStackTrace();
            log.error("[login] 登录逻辑出现错误 msg={}", var3);
        }
    }


    @NotNull
    private static UserWrap makeUserWrap(LoginMqWrap body, UpMsgLoginReq loginReq, UserDTO userInfo, List<UserDevice> devices) {
        UserWrap userWrap = new UserWrap();
        userWrap.setNick(userInfo.getNickname());

        UserDevice deviceInfo = new UserDevice();
        deviceInfo.setMqTags(body.getMqTags());
        deviceInfo.setDubboIp(body.getClientIp());
        deviceInfo.setDubboPort(body.getDubboPort());
        deviceInfo.setUserIp(body.getClientIp());
        deviceInfo.setDeviceType(loginReq.getDeviceType());

        if (CollUtil.isEmpty(devices)) {
            userWrap.setDeviceInfos(List.of(deviceInfo));
        } else {
            devices.add(deviceInfo);
            userWrap.setDeviceInfos(devices);
        }

        userWrap.setAppKey(userInfo.getAppKey());
        userWrap.setFirstLoginIp(body.getClientIp());
        userWrap.setUserId(userInfo.getUserId());
        userWrap.setAvatar(userInfo.getAvatarUrl());
        userWrap.setStatus(userInfo.getStatus());

        return userWrap;
    }


}
